package com.example.hello.service.impl;

import com.example.hello.service.FileStorageService;
import io.minio.*;
import io.minio.http.Method;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service("fileStorageServiceImpl")
public class FileStorageServiceImpl implements FileStorageService {

    private static final Logger logger = LogManager.getLogger(FileStorageServiceImpl.class);

    @Autowired
    private MinioClient minioClient;

    @Value("${object.storage.bucket-name}")
    private String bucketName;

    @Value("${object.storage.public-url}")
    private String publicUrl;

    @Override
    public String uploadFile(MultipartFile file, String directory) throws IOException {
        String originalFilename = file.getOriginalFilename();
        String extension = getFileExtension(originalFilename);
        String objectKey = generateObjectKey(directory, extension);
        
        int maxRetries = 3;
        int retryCount = 0;
        Exception lastException = null;
        
        while (retryCount < maxRetries) {
            try {
                logger.info("尝试上传文件到对象存储: {}/{}", bucketName, objectKey);
                
                // 使用 MinIO 客户端上传文件
                minioClient.putObject(
                    PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectKey)
                        .contentType(file.getContentType())
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .build()
                );
                
                // 对于公共读取的存储桶，直接返回URL
                String fileUrl = String.format("%s/%s", publicUrl, objectKey);
                logger.info("文件上传成功: {}", fileUrl);
                return fileUrl;
            } catch (Exception e) {
                lastException = e;
                logger.warn("文件上传失败，尝试重试 ({}/{}): {}", retryCount + 1, maxRetries, e.getMessage());
                retryCount++;
                
                // 等待一段时间再重试
                try {
                    Thread.sleep(1000 * retryCount);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new IOException("文件上传被中断", ie);
                }
            }
        }
        
        logger.error("文件上传失败，已达到最大重试次数: {}", lastException.getMessage());
        throw new IOException("文件上传失败: " + lastException.getMessage(), lastException);
    }

    @Override
    public Map<String, String> uploadFiles(List<MultipartFile> files, String directory) throws IOException {
        Map<String, String> result = new HashMap<>();
        
        for (MultipartFile file : files) {
            String fileUrl = uploadFile(file, directory);
            result.put(file.getOriginalFilename(), fileUrl);
        }
        
        return result;
    }

    @Override
    public boolean deleteFile(String fileUrl) {
        try {
            String objectKey = fileUrl.replace(publicUrl + "/", "");
            
            // 使用 MinIO 客户端删除文件
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectKey)
                    .build()
            );
            
            logger.info("文件删除成功: {}", fileUrl);
            return true;
        } catch (Exception e) {
            logger.error("文件删除失败", e);
            return false;
        }
    }

    @Override
    public String generatePresignedUrl(String objectKey, int expirationMinutes) {
        try {
            // 使用 MinIO 客户端生成预签名URL
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .bucket(bucketName)
                    .object(objectKey)
                    .method(Method.GET)
                    .expiry(expirationMinutes, TimeUnit.MINUTES)
                    .build()
            );
            
            logger.info("生成预签名URL成功: {}", presignedUrl);
            return presignedUrl;
        } catch (Exception e) {
            logger.error("生成预签名URL失败", e);
            return null;
        }
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null) {
            return "";
        }
        int dotIndex = filename.lastIndexOf('.');
        if (dotIndex < 0) {
            return "";
        }
        return filename.substring(dotIndex);
    }

    /**
     * 生成对象键
     */
    private String generateObjectKey(String directory, String extension) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return String.format("%s/%s%s", directory, uuid, extension);
    }
} 